﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Test.Account.common;
using Test.Common.Exceptions;
using Test.DataAccess.POCO;
using Test.Utility.Extensions;

namespace Test.Account.Manager
{
    public  class AdminManager:ManagerBase
    {
        #region ValidateUser

        public virtual bool ValidateAdmin(string adminName, string password)
        {
            bool isLockedOut;
            return ValidateAdmin(adminName, password, out isLockedOut);
        }

        public virtual bool ValidateAdmin(string adminName, string password, out bool isLockout)
        {
            var admin = AdminProvider.Get(a => a.UserName == adminName);
            isLockout = false;

            Setting setting = this.SettingProvider.Get();

            bool valid = false;
            if (admin != null)
            {
                var encodedPassword = PasswordProvider.EncryptPassword(password);
                valid = encodedPassword == admin.Password;

                //超时解锁
                if (admin.IsLockedOut && admin.LastLockoutDate.HasValue
                    && admin.LastLockoutDate.Value.AddMinutes(setting.MinutesToUnlock) < DateTime.Now)
                {
                    admin.FailedPasswordAttemptCount = 0;
                    admin.IsLockedOut = false;
                }

                //验证成功
                if (valid)
                {
                    admin.FailedPasswordAttemptCount = 0;
                    admin.IsLockedOut = isLockout = false;
                    admin.LastLoginDate = DateTime.Now;
                }
                else//锁定账户
                {
                    admin.FailedPasswordAttemptCount++;
                    if (admin.FailedPasswordAttemptCount >= setting.FailedPasswordAttemptCount)
                    {
                        admin.IsLockedOut = isLockout = true;
                        admin.LastLockoutDate = DateTime.Now;
                    }
                }

                Update(admin);
            }
            return valid;
        }

        #endregion

        #region Get

        public virtual Admin Get(string adminName)
        {
            return AdminProvider.Get(a => a.UserName == adminName);
        }
        public virtual Admin GetById(string id)
        {
            return AdminProvider.GetById(id);
        }

        public virtual Admin Get(Expression<Func<Admin, bool>> predicate)
        {
            return AdminProvider.Get(predicate);
        }

        #endregion

        #region Update

        public virtual void Update(Admin admin)
        {
            #region Validate data

            ValidateData(admin, false);

            #endregion

            AdminProvider.Update(admin);
        }

        #endregion

        #region Add

        public virtual bool Add(Admin admin)
        {
            #region Validate data

            ValidateData(admin);

            #endregion

            admin.Password = PasswordProvider.EncryptPassword(admin.Password);

            return AdminProvider.Insert(admin) > 0;
        }

        #endregion

        #region Delete

        public virtual bool Delete(string adminName)
        {
            return AdminProvider.Delete(a => a.UserName == adminName) > 0;
        }

        public virtual bool Delete(Expression<Func<Admin, bool>> predicate)
        {
            return AdminProvider.Delete(predicate) > 0;
        }

        #endregion

        #region All

        public virtual IEnumerable<Admin> All()
        {
            return AdminProvider.Entities.AsEnumerable();
        }

        #endregion

        #region ChangePassword

        public virtual bool ChangePassword(string adminName, string oldPassword, string newPassword)
        {
            if (!ValidateAdmin(adminName, oldPassword))
            {
                return false;
            }
            return ChangePassword(adminName, newPassword);
        }

        public virtual bool ChangePassword(string adminName, string newPassword)
        {
            var admin = AdminProvider.Get(a => a.UserName == adminName);

            if (admin == null)
            {
                throw new ArgumentException("The member doest not exists.");
            }

            admin.Password = PasswordProvider.EncryptPassword(newPassword); ;

            Update(admin);

            return true;
        }

        public virtual bool SetIfChangePassword(Admin admin, string oldPassword, string newPassword)
        {
            if (newPassword.IsNotNullAndNotWhiteSpace())
            {
                if (PasswordProvider.EncryptPassword(oldPassword) != admin.Password)
                {
                    return false;
                }
                admin.Password = PasswordProvider.EncryptPassword(newPassword);
            }
            return true;
        }

        #endregion

        #region Permissions

        public virtual IEnumerable<Permission> GetAllPermissions(string adminName)
        {
            return AdminProvider.Get(a => a.UserName == adminName).Roles.SelectMany(r => r.Permissions).Distinct().AsEnumerable();
        }

        #endregion

        private void ValidateData(Admin admin, bool creating = true)
        {
            List<DataViolationItem> violations = new List<DataViolationItem>();

            if (creating && AdminProvider.Get(a => a.UserName == admin.UserName) != null)
            {
                violations.Add(new DataViolationItem("UserName", admin.UserName, "用户名被占用"));
            }
            if (!creating && AdminProvider.Get(a => a.UserName == admin.UserName && a.Id != admin.Id) != null)
            {
                violations.Add(new DataViolationItem("UserName", admin.UserName, "用户名被占用"));
            }
            if (string.IsNullOrEmpty(admin.Password))
            {
                violations.Add(new DataViolationItem("Password", admin.Password, "密码格式无效"));
            }

            if (violations.Count > 0)
            {
                throw new DataViolationException(violations);
            }
        }
    }
}
